#include "t0022-0.h"
#include "dxtviewer.h"
#include "appwidget.h"
#include "cui.h"
#include <signal.h>

#define MODNAME     "[APDAT]"
static struct l0032_xtable_entry* menubar_current_entry(struct cui_widget_st* widget);
static int dataview_load(struct cui_widget_st *widget, struct l0032_xtable *xtable);
static int dataview_keyevent(struct cui_widget_st* widget, int key, struct appdata_st *appdata);
extern struct dxtviewer_st dv;

int popload(struct appdata_st *appdata)
{
    int retval = -1;
	ERRSYS_INFOPRINT("%s entry %p index %d %p\n", __func__, appdata->entry, appdata->point_index, appdata->entry->namedpoints);
    if (appdata && appdata->entry) {
        struct l0032_xtable_entry *entry = appdata->entry;
        struct l0032_xtable_namedpoint *namedpoints = entry->namedpoints;
        if (namedpoints && namedpoints[appdata->point_index].flags & L0032_DXT_FLAGS_POINT_VALUEENUM) {
            popmenu_load(appdata);
        }
        else {
            popform_load(appdata);
        }
        retval = 0;
    }

    return retval;
}

/*
	appdata(window)
	/			\
menubar(menu)	dataviewer(window)

-----------------------------------------------------------------
|			title:<dxtable_appname>								|
|----------------------------------------------------------------
|MENUBAR		|DATAVIWER										|
|<entry_name1>	|<point_name>:value								|
|<entry_name1>	|<point_name>:value								|
|<entry_name1>	|												|
|<entry_name1>	|												|
|				|												|
|				|												|
|				|												|
----------------|												|
|	desc		|												|
-----------------------------------------------------------------
*/

int datadesc_paint(struct cui_widget_st* widget, int dummy)
{
	struct cui_widget_st *widget_desc;
	struct l0032_xtable_entry *entry;
	struct appdata_st *appdata = widget->priv;
	static char desc[L0032_DXT_DESC_MAX_LEN * 2]= {0};
	int point_index = 0;
	struct l0032_xtable_namedpoint *namedpoints;

	ERRSYS_INFOPRINT("!!!!! %s:[%s]\n", __func__, widget->name);
	widget_desc = get_widget_byname(&widget->cscr->windowlist, "datadesc");
	entry = appdata->entry;
	// ERRSYS_INFOPRINT("entry %p %d\n", entry, appdata->input_statmach);
	memset(desc, 0, L0032_DXT_DESC_MAX_LEN * 2);

	if (entry) {
		point_index = appdata->point_index;
		namedpoints = entry->namedpoints;

		if (appdata->input_statmach == APPDATA_INPUTSTATMACH_MENUBAR) {
			// desc = appdata->entry->desc;
			snprintf(desc, L0032_DXT_DESC_MAX_LEN * 2, "ENTRY: %s", appdata->entry->desc);
		}
		else {
			if (namedpoints) {
				// desc = appdata->entry->namedpoints[point_index].desc;
				snprintf(desc, L0032_DXT_DESC_MAX_LEN * 2, "POINT[%d]: %s", point_index, appdata->entry->namedpoints[point_index].desc);
			}
		}
	}
	if (strlen(desc) == 0) {
		snprintf(desc, L0032_DXT_DESC_MAX_LEN * 2, "No description");
	} 

	// entry = menubar_current_entry(widget);
	// cui_dump_widget(widget_desc);
	
	cui_print_autoreturn(widget_desc, 0, 0, desc, WHTBLK);

	return 0;
}

int menubar_load(struct cui_widget_st *widget, struct l0032_xtable *xtable)
{
	int i;
	struct cui_widget_st *widget_menubar = get_widget_byname(&widget->cscr->windowlist, "menubar");
	if (widget_menubar) {
		const char **ppentries;
		ppentries = zmalloc(sizeof(char*) * xtable->nentries);
		if (ppentries) {
			for (i = 0;i < xtable->nentries;i ++) {
				struct l0032_xtable_entry *entry = &xtable->entries[i];
				int indent = 2;
				ERRSYS_INFOPRINT("----------entry[%d]----------\n", i);
				ERRSYS_INFOPRINT("%*s name: %s\n", indent, "", entry->name);
				ERRSYS_INFOPRINT("%*s desc: %s\n", indent, "", entry->desc);
				ERRSYS_INFOPRINT("%*s flags: %s\n", indent, "", l0032_xtable_dump_entry_flags(entry));
				ppentries[i] = entry->name;
			}
			cui_menu_initialize(widget_menubar, xtable->nentries, ppentries, NULL, -1);

			free(ppentries);
		}
		else {
			ERRSYS_FATALPRINT("%s:fail to malloc for ppentries!\n", __func__);
		}
	}
	else {
		ERRSYS_FATALPRINT("%s:menubar not found!\n", __func__);
	}

	return 0;
}

static struct l0032_xtable_entry* menubar_current_entry(struct cui_widget_st* widget)
{
	struct l0032_xtable_entry *entry = NULL;
	int index = 0;
	struct cui_menu_st* cmenu;
	ITEM *item;
	struct cui_widget_st* widget_menubar = get_widget_byname(&widget->cscr->windowlist, "menubar");
	if (widget_menubar) {
		cmenu = widget_menubar->widgetinstance;
		item = current_item(cmenu->menu);
		index = item_index(item);
		if (index < 0) {
			/* may not choosen yet, index return -1 */
			index = 0;
		}
		entry = &dv.xtable.entries[index];
		ERRSYS_INFOPRINT("[%s] current item \"%s\" index %d\n", widget_menubar->name, item_name(item), index);
	}

	return entry;
}

int menubar_keyevent(struct cui_widget_st* widget, int key, struct appdata_st *appdata)
{
	int handled = CUI_WIDGETEVENT_PROPAGATION;
	struct cui_widget_st *widget_menubar = NULL;
	ERRSYS_INFOPRINT("%s:%s\n", widget->name, __func__);
	switch (key) {
		case KEY_ENTER_US:
			key = KEY_ENTER;
		case KEY_ENTER:
		case KEY_DOWN:
		case KEY_UP:
		case KEY_RIGHT:
		case KEY_ESC:
			handled = CUI_WIDGETEVENT_HANDLED;
			break;
	}

	if (KEY_UP == key || KEY_DOWN == key) {
		dataview_load(widget, &dv.xtable);
		cui_refresh(widget->cscr, -1);
		ERRSYS_INFOPRINT("!!!! done\n");
	}
	else if (KEY_ENTER == key) {
		widget_menubar = get_widget_byname(&widget->cscr->windowlist, "menubar");
		appdata->input_statmach = APPDATA_INPUTSTATMACH_DATAVIEW;
		/* 重置point index */
		appdata->point_index = 0;
		SET_WIDGET_KEYEVENTOFF(widget_menubar);
		ERRSYS_INFOPRINT("statmach set APPDATA_INPUTSTATMACH_DATAVIEW\n");
		dataview_keyevent(widget, KEY_UP, appdata);	// first time enter "APPDATA_INPUTSTATMACH_DATAVIEW". Input key set to KEY_UP, to go KEY_UP procedure
	}
	else if (KEY_ESC == key) {
		cui_screen_pop(widget->cscr);
		cui_refresh(widget->cscr, -1);
		ERRSYS_INFOPRINT("appdata quit\n");
	}

	return handled;
}

int dataview_panel_count(struct cui_widget_st* widget)
{
	int i = 0;
	struct list_head *pos;
	list_for_each(pos, &widget->widgetlist) {
		i ++;
	}
	ERRSYS_INFOPRINT("%s %d panels\n", widget->name, i);
	return i;
}

static void dataview_load_widget(struct cui_widget_st* widget, struct l0032_xtable_entry *entry)
{
	struct cui_widget_st* widget_dataview = get_widget_byname(&widget->cscr->windowlist, "dataview");
	if (widget_dataview != NULL && entry != NULL) {
		cui_panel_reset_template(widget_dataview);
		cui_panel_duplicate(widget_dataview, entry->npoints);
		cui_panel_rearrange(widget_dataview, PANEL_REARRANGE_ROW);
	}
}

#define LABEL_PTNAME		0
#define LABEL_PTVALUE		1

static void dataview_load_data(struct cui_widget_st* widget, struct l0032_xtable_entry *entry)
{
	struct cui_widget_st* widget_dataview = get_widget_byname(&widget->cscr->windowlist, "dataview");
	if (widget_dataview != NULL && entry != NULL) {
		int *val;
		int npoints;

		npoints = entry->npoints;
		ERRSYS_INFOPRINT("name: %s\n", entry->name);
		ERRSYS_INFOPRINT("desc: %s\n", entry->desc);
		ERRSYS_INFOPRINT("npoints: %d\n", entry->npoints);
		ERRSYS_INFOPRINT("flags: %s\n", l0032_xtable_dump_entry_flags(entry));

		val = zmalloc(npoints * sizeof(int));

		if (val != NULL) {
			struct cui_widget_st *widget_panel;
			int i;
			for (i = 0;i < npoints;i ++) {
				l0032_xtable_read(entry->hentry, i, &val[i], sizeof(int));
				ERRSYS_INFOPRINT("%s:[%d] read value:%d total %d\n", __func__, i, val[i], npoints);
			}
			i = 0;
			list_for_each_entry(widget_panel, &widget_dataview->widgetlist, node) {
				ERRSYS_INFOPRINT("widget panel %p\n", widget_panel);
				if (widget_panel->nlabels > LABEL_PTVALUE) {
					struct l0032_xtable_namedpoint *namedpoints = entry->namedpoints;
					ERRSYS_INFOPRINT("npoints %d i %d\n", entry->npoints, i);
					if (namedpoints && namedpoints[i].flags & L0032_DXT_FLAGS_POINT_VALUEENUM) {
						// 有名point且有枚举值
						int j;
						ERRSYS_INFOPRINT("[%d] name %s, desc %s, nvalues %d\n", i, namedpoints[i].name, namedpoints[i].desc, namedpoints[i].nvalues);
						// label point name
						cui_label_printf(widget_panel, LABEL_PTNAME, "[%d] %s", i, namedpoints[i].name);
						// label point value
						for (j = 0;j < namedpoints[i].nvalues;j ++) {
							struct l0032_xtable_valueenum *valueenum = &namedpoints[i].valueenum[j];
							ERRSYS_INFOPRINT("valueenum->val %d val[%d] %d\n", valueenum->val, i, val[i]);
							if (valueenum->val == val[i]) {
								cui_label_printf(widget_panel, LABEL_PTVALUE, " =: %d-<%s>", val[i], valueenum->valdesc);
								break;
							}
						}
						if (j == namedpoints[i].nvalues) {
							cui_label_printf(widget_panel, LABEL_PTVALUE, " =: %d-<INVALID VALUE>", val[i]);
						}
					}
					else {
						// 无名point
						cui_label_printf(widget_panel, LABEL_PTNAME, "[%d] noname", i);
						cui_label_printf(widget_panel, LABEL_PTVALUE, " =: %d", val[i]);
					}

					ERRSYS_INFOPRINT("PANEL[%s] name [%s] %d\n", widget_panel->name, widget_panel->clabel[LABEL_PTVALUE].text, widget_panel->nlabels);
				}
				i ++;
			}

			free(val);
		}
	}

	return;	
}

static int dataview_keyevent(struct cui_widget_st* widget, int key, struct appdata_st *appdata)
{
	int handled = CUI_WIDGETEVENT_PROPAGATION;
	struct cui_widget_st *widget_dataview = NULL;
	ERRSYS_INFOPRINT("%s:%s\n", widget->name, __func__);
	switch (key) {
		case KEY_ENTER_US:
			key = KEY_ENTER;
		case KEY_ENTER:
		case KEY_DOWN:
		case KEY_UP:
		case KEY_ESC:
			handled = CUI_WIDGETEVENT_HANDLED;
			break;
	}

	widget_dataview = get_widget_byname(&widget->cscr->windowlist, "dataview");

	if (widget_dataview) {
		if (KEY_UP == key || KEY_DOWN == key) {
			int point_index_last = appdata->point_index;
			if (KEY_UP == key) {
				appdata->point_index -= 1;
				if (appdata->point_index < 0) {
					appdata->point_index = 0;
				}
			}
			else if (KEY_DOWN == key) {
				int n = dataview_panel_count(widget_dataview);
				appdata->point_index += 1;
				if (appdata->point_index >= n) {
					appdata->point_index = n - 1;
				}
			}
			ERRSYS_INFOPRINT("dataview index %d last %d\n", appdata->point_index, point_index_last);
			if (!list_empty(&widget_dataview->widgetlist)) {
				int i = 0;
				struct cui_widget_st *widget;
				// struct cui_panel_st *panel;
				list_for_each_entry(widget, &widget_dataview->widgetlist, node) {
					if (i == point_index_last) {
						ERRSYS_INFOPRINT("Panel [%s] is unhighlighted\n", widget->name);
						UNSET_WIDGET_HIGHLIGHT(widget);
						cui_refresh(widget->cscr, -1);
					}
					if (i == appdata->point_index) {
						/* highlight the first panel */
						ERRSYS_INFOPRINT("Panel [%s] is highlighted\n", widget->name);
						SET_WIDGET_HIGHLIGHT(widget);
						cui_refresh(widget->cscr, -1);
					}
					i ++;
				}
			}
		}
		else if (KEY_ESC == key) {
			struct cui_widget_st *widget_menubar = get_widget_byname(&widget->cscr->windowlist, "menubar");
			appdata->input_statmach = APPDATA_INPUTSTATMACH_MENUBAR;
			appdata->entry = menubar_current_entry(widget);
			appdata->point_index = 0;
			list_for_each_entry(widget, &widget_dataview->widgetlist, node) {
				UNSET_WIDGET_HIGHLIGHT(widget);
				cui_refresh(widget->cscr, -1);
			}
			UNSET_WIDGET_KEYEVENTOFF(widget_menubar);
			ERRSYS_INFOPRINT("statmach set APPDATA_INPUTSTATMACH_MENUBAR\n");
		}
		else if (KEY_ENTER == key) {
			popload(appdata);
		}

	}
	else {
		ERRSYS_FATALPRINT("dataview not found!\n");
	}


	return handled;
}

static int dataview_load(struct cui_widget_st *widget, struct l0032_xtable *xtable)
{
	struct l0032_xtable_entry *entry;
	struct appdata_st *appdata = widget->priv;

	entry = menubar_current_entry(widget);

	// ERRSYS_INFOPRINT("!!!! dataview_load_widget\n");
	dataview_load_widget(widget, entry);
	// ERRSYS_INFOPRINT("!!!! dataview_load_data\n");
	dataview_load_data(widget, entry);
	appdata->entry = entry;

	return 0;
}

int appdata_keyevent(struct cui_widget_st* widget, int key)
{
    int handled = CUI_WIDGETEVENT_PROPAGATION;
	// ERRSYS_INFOPRINT("%s:%s\n", widget->name, __func__);

	if (widget->priv != NULL) {
		struct appdata_st *appdata = widget->priv;
		if (IS_INPUTSTATMACH_MENUBAR(appdata)) {
			handled = menubar_keyevent(widget, key, appdata);
		}
		else if (IS_INPUTSTATMACH_DATAVIEW(appdata)) {
			handled = dataview_keyevent(widget, key, appdata);
		}
	}

    return handled;
}

int appdata_paint(struct cui_widget_st* widget, int dummy)
{
	struct l0032_xtable_entry *entry;

	ERRSYS_INFOPRINT("%s %s\n", __func__, widget->name);
	entry = menubar_current_entry(widget);
	dataview_load_data(widget, entry);
	datadesc_paint(widget, dummy);
	return 0;
}

/* 加载app条目到menubar，并且加载第一个app条目的所有数据 */
int appdata_load(const char *filepath)
{
    int retval = -1;
	struct cui_widget_st *widget = get_widget_byname(&dv.cscr->windowlist, "appdata");
	static char title[CUI_WIDGETTITLE_BUFLEN] = {0};

	if (widget != NULL) {
		if (filepath != NULL) {
			// open dataxchgtable.
			if(l0032_xtable_open(NULL, 0) == NULL) {
				ERRSYS_FATALPRINT("Fail to open Data Exchange Table\n");
				goto err1;
			}
			ERRSYS_INFOPRINT("%s:xtable is opened\n", __func__);
			// parse dxt conf.
			if(l0032_xtable_load_conf(&dv.xtable, filepath) != 0) {
				ERRSYS_FATALPRINT("xtable load failed, iniconf:%s\n", filepath);
				goto err2;
			}
			ERRSYS_INFOPRINT("%s:xtable is loaded\n", __func__);
		}
		// 提取文件名作为appdata的title
		extract_filename(filepath, title);
		ERRSYS_INFOPRINT("[%s]%s title %s\n", widget->name, __func__, title);
		cui_set_widget_title(widget, title);

		menubar_load(widget, &dv.xtable);
		dataview_load(widget, &dv.xtable);
		
		// 当前widget压入screen stack
		cui_screen_push(widget, NULL);
		cui_refresh(widget->cscr, -1);

		retval = 0;

	}
	else {
		ERRSYS_FATALPRINT("widget not found!\n");
		goto err2;
	}

err1:
	if (retval < 0) {
		widget->ops.destroy(widget);
	} 

err2:
    return retval;
}

void appdata_destroy(struct cui_widget_st* widget)
{
	if (widget->widgetinstance != NULL) {
		free(widget->widgetinstance);
		widget->widgetinstance = NULL;
	}
	if (widget->priv) {
		free(widget->priv);
		widget->priv = NULL;
	}
	l0032_xtable_close();
}

int appdata_initialize(struct cui_widget_st* widget)
{
	int retval = -1;
	struct appdata_st *appdata = zmalloc(sizeof(struct appdata_st));
	if (appdata != NULL) {
		// struct cui_widget_st *widget_desc;
		// widget_desc = get_widget_byname(&widget->cscr->windowlist, "datadesc");
		widget->priv = appdata;
	
		appdata->input_statmach = APPDATA_INPUTSTATMACH_MENUBAR;
		cui_set_widget_eventslot(widget, CUI_EVENTCB_TYPE_PAINT, appdata_paint);
		retval = 0;
	}

	ERRSYS_INFOPRINT("[%s]%s\n", widget->name, __func__);
	return retval;
}

EXPORT_WIDGET_INITIALIZE(appdata_initialize);
